Bit Manipulation π
Adding 1 to a numberβ
Adding 1 to a number sets the rightmost unset bit and clears all the
1s to its right.
Adding 1 to a binary number causes binary addition with carry.
- Effect on the rightmost bits:
- If the rightmost bit is
0, adding1turns it into1. β - If the rightmost bit is
1, adding1causes a carry, flipping consecutive1s to0s until a0is encountered, which then becomes1.
- If the rightmost bit is
So, adding 1 actually sets the rightmost 0 bit to 1 and resets all the 1s to 0 that were to its right.
Operatorβ
AND (&)β
0 & 0 = 0
0 & 1 = 0
1 & 0 = 0
1 & 1 = 1
-
0dominates β if any bit is0, the result becomes0. -
Keep specific bit: AND with a mask that has
1only at the desired position so all other bits become0.1101
0100
^
----
0100 -
Check/Clear bit: AND with
(1 << i)to check if thei-th bit is set, or AND with~(1 << i)to clear that bit while keeping others unchanged.1101
1011
^
----
1001
OR (|)β
0 | 0 = 0
0 | 1 = 1
1 | 0 = 1
1 | 1 = 1
1dominates β if any bit is1, the result becomes1.
XOR (^)β
0 ^ 0 = 0
0 ^ 1 = 1
1 ^ 0 = 1
1 ^ 1 = 0
- Same β 0, Different β 1
- XOR toggles the bit
0 ^ 0 = 0
1 ^ 0 = 1
---------
0 ^ 1 = 1
1 ^ 1 = 0
- XOR with 0 β keeps the bit same
- XOR with 1 β flips (toggles) the bit
XOR of numbers shows which bits differβ
If two bits are different β result is 1, meaning that position is different.
5 ^ 5 = 0101 ^ 0101 = 0000 β no difference
5 ^ 4 = 0101 ^ 0100 = 0001 β difference at last bit
NOT (~)β
~0 = 1
~1 = 0
- Flips every bit (0 β 1, 1 β 0).
- Also called bitwise complement.
Twoβs Complementβ
One's Complement of x is ~x, So Two's complement is:
- x = (~x) + 1
Left Shift (<<)β
Moves bits to the left.
a << n
- Means shift bits left by
npositions.
5 << 1
00001010 = 10
Rule
x << n = x Γ 2βΏ
Right Shift (>>)β
Moves bits to the right.
a >> n
- Means shift bits right by
npositions.
20 >> 1
00001010 = 10
Rule
x >> n = x / 2βΏ
Operationβ
Set Bitβ
Goal:
0 β 1
1 β 1
ANDβ
0 & 1 = 0
1 & 1 = 1
- Results depends on original bits
ORβ
0 | 1 = 1
1 | 1 = 1
- Results depends on mask bit
XORβ
0 ^ 0 = 0
1 ^ 0 = 1
------
0 ^ 1 = 1
1 ^ 1 = 0
If the bit was already 1, xor turns it into 0(1 ^ 1 = 0)
Check Set Bitβ
Goal
- Target bit β unknown (
0or1) - Mask bit β fixed
ANDβ
0 & 0 = 0
1 & 0 = 0
---------
0 & 1 = 0
1 & 1 = 1
Observation:
- If mask =
0, result is always0β cannot distinguish β eliminate. - If mask =
1, result depends on the original bit.
So AND works if mask = 1.
ORβ
0 || 0 = 0
1 || 0 = 1
----------
0 || 1 = 1
1 || 1 = 1
Observation:
- If mask =
1, result always1β cannot distinguish. - If mask =
0, result = original bit.
But we cannot isolate a specific bit using OR, because:
- All other bits also remain unchanged.
- OR does not zero out the other bits.
XORβ
0 ^ 0 = 0
1 ^ 0 = 1
------
0 ^ 1 = 1
1 ^ 1 = 0
Observation:
- XOR changes the bit (toggle).
- It does not preserve the original value.
Clear Bitβ
Goal
0 β 0
1 β 0
0 dominates in AND operator.
Swapping Two Numberβ
A = A ^ B
B = A ^ B = (A ^ B) ^ B = A ^ B ^ B = A
A = A ^ B = (A ^ B) ^ A = A ^ B ^ A = B
XOR of Rangeβ
- xor of two same number return 0 (
a β a = 0) - xor of any number with 0 return itself (
a β 0 = a)
| n | xor[0..n] | Calculation | Result |
|---|---|---|---|
| 0 | xor[0,0] | 0 | 0 |
| 1 | xor[0,1] | 0 β 1 | 1 |
| 2 | xor[0,2] | 0 β 1 β 2 | 3 |
| 3 | xor[0,3] | 0 β 1 β 2 β 3 | 0 |
| 4 | xor[0,4] | 0 β 1 β 2 β 3 β 4 | 4 |
| 5 | xor[0,5] | 0 β 1 β 2 β 3 β 4 β 5 | 1 |
| 6 | xor[0,6] | 0 β 1 β 2 β 3 β 4 β 5 β 6 | 7 |
| 7 | xor[0,7] | 0 β 1 β 2 β 3 β 4 β 5 β 6 β 7 | 0 |
| 8 | xor[0,8] | 0 β 1 β 2 β 3 β 4 β 5 β 6 β 7 β 8 | 8 |
XOR from 0 to nβ
Thereβs a simple repeating pattern:
| n % 4 | xor(n) |
|---|---|
| 0 | n |
| 1 | 1 |
| 2 | n + 1 |
| 3 | 0 |
- Everything from
0tolβ1appears twice and cancels out - Only values from
lto r remain
Number of Set Bitβ
Brian Kernighanβs Algorithmβ
Remove the rightmost set bit every iteration.
int countSetBits(int n) {
int count = 0;
while (n) {
n = n & (n - 1);
count++;
}
return count;
}
Lowest Set Bit / Right Most Bitβ
The rightmost
1in the binary representation
It can be usefull to iterate through the bit efficiently
while(x){
int bit = x & -x;
cout << bit << endl;
x -= bit;
}
Example:
x = 13 (1101)
lowest bit = 0001
next = 0100
next = 1000
Number of Set Bits in a Series (1...N)β
Count set bits position by position using patterns in binary numbers.
Binary numbers repeat patterns every 2^k.
Dry Run (N = 5)β
| Decimal | Bit 2 | Bit 1 | Bit 0 |
|---|---|---|---|
| 1 | 0 | 0 | 1 |
| 2 | 0 | 1 | 0 |
| 3 | 0 | 1 | 1 |
| 4 | 1 | 0 | 0 |
| 5 | 1 | 0 | 1 |
Bit position 0β
Pattern: 0 1 0 1 0 1
Set bits = 3
Bit position 1β
Pattern: 0 0 1 1 0 0
Set bits = 2
Bit position 2β
Pattern: 0 0 0 0 1 1
Set bits = 2
Total set bits: 3 + 2 + 2 = 7
int countSetBits(int n) {
int total = 0;
for (int i = 0; (1LL << i) <= n; i++) {
int cycleLen = 1 << (i + 1); // 1 << i + 1 = 2^(i+1)
// Count set bits in full cycles for bit 'i'
int fullCycles = (n + 1) / cycleLen;
total += fullCycles * (1 << i);
// Count set bits in remaining part of the cycle
int remainder = (n + 1) % cycleLen;
total += (remainder > (1 << i)) ? (remainder - (1 << i)) : 0;
}
return total;
}
Loop runs while
2^i β€ n
Iteration 1β
i = 0
1 << i = 1 << 0 = 1
Cycle length:
cycleLen = 1 << (i + 1)
= 1 << 1
= 2
Full cycles
fullCycles = (n + 1) / cycleLen
= (5 + 1) / 2
= 3
Each cycle contributes:
1 << i = 1
So
total += 3 * 1 = 3
Remainder
remainder = (n + 1) % cycleLen
= 6 % 2
= 0
Extra bits:
remainder > 1 ? no
Total so far
total = 3
Iteration 2β
i = 1
1 << i = 1 << 1 = 2
Cycle length
cycleLen = 1 << 2 = 4
Full cycles
fullCycles = 6 / 4 = 1
Contribution
total += 1 * 2 = 2
Total
total = 5
Remainder
remainder = 6 % 4 = 2
Check extra
remainder > 2 ? no
Total remains
5
Iteration 3β
i = 2
1 << i = 1 << 2 = 4
Cycle length
cycleLen = 1 << 3 = 8
Full cycles
fullCycles = 6 / 8 = 0
Contribution
total += 0
Remainder
remainder = 6 % 8 = 6
Extra bits
6 > 4 β yes
extra = 6 - 4 = 2
Total
total = 5 + 2 = 7
Loop Endsβ
Next
1 << 3 = 8
8 > 5
Loop stops.
Final answer
7
Questionβ
How computers store negative numbers
Computers store all data in binary (bits: 0 and 1). For signed integers, they use a system called: Two's Complement
Example (8-bit system)
Store +5
00000101
Store -5
Step 1: binary of 5
00000101
Step 2: invert bits
11111010
Step 3: add 1
11111011 β this is -5
Why this works
Twoβs complement allows:
- Simple addition/subtraction
- Same hardware for positive & negative
- No separate βsign handlingβ
Range of Data Types
The range depends on: Number of bits (n)
General Formula
For signed integers (twoβs complement):
- Minimum = β2^(nβ1)
- Maximum = 2^(nβ1) β 1
Why range is asymmetric?
Example (8-bit):
- Range: β128 to +127
One extra negative value exists because:
00000000= 010000000= β128 (special case)